package xyz.yq56.easytool.utils.io;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import lombok.extern.slf4j.Slf4j;

/**
 * @author yi qiang
 * @date 2021/11/23 0:04
 */
@Slf4j
public class ZipUtil {

    private ZipUtil() {
    }

    /**
     * Zip 工具类
     *
     * @param out         包装outputStream为ZipOutPutStream
     * @param inputStream 输入流,即希望打包的文件流
     * @param fileName    文件绝对路径(包含文件名称),如 /data/test.jpg
     */
    public static void doZip(ZipOutputStream out, InputStream inputStream, String fileName) {
        try {
            //包装成缓冲流
            try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
                ZipEntry entry = new ZipEntry(fileName);
                out.putNextEntry(entry);
                byte[] byt = new byte[1024 * 8];
                int len;
                while ((len = bufferedInputStream.read(byt)) != -1) {
                    out.write(byt, 0, len);
                }
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
            }
        } catch (IOException e) {
            log.warn("ZipUtil | doZip: {}", e.getMessage(), e);
        }
    }

    /**
     * Zip 工具类
     *
     * @param out      包装outputStream为ZipOutPutStream
     * @param bytes    字节数组,即希望打包的文件流
     * @param fileName 文件绝对路径(包含文件名称),如 /data/test.jpg
     */
    public static void doZip(ZipOutputStream out, byte[] bytes, String fileName) {
        log.debug("bytes: {},fileName: {}", bytes, fileName);
        doZip(out, new ByteArrayInputStream(bytes), fileName);
    }

    /**
     * 解压文件
     *
     * @param zipFile 压缩文件
     */
    public static Map<String, byte[]> unZip(File zipFile, Charset charset) {
        Map<String, byte[]> map = new HashMap<>(8);
        try {
            try (ZipFile zip = new ZipFile(zipFile, charset)) {
                Enumeration<? extends ZipEntry> zipEntries = zip.entries();
                while (true) {
                    if (!zipEntries.hasMoreElements()) {
                        return map;
                    }
                    ZipEntry entry = zipEntries.nextElement();
                    String entryName = entry.getName();
                    InputStream in = zip.getInputStream(entry);
                    map.put(entryName, IoUtil.readInputStream(in));
                }
            }
        } catch (IOException e) {
            log.warn("ZipUtil | unZip: {}", e.getMessage(), e);
        }
        return Collections.emptyMap();
    }

    public static Map<String, byte[]> unZip(File zipFile) {
        try {
            return unZip(zipFile, Charset.defaultCharset());
        } catch (IllegalArgumentException e) {
            log.warn("使用默认字符集解压失败,尝试使用GBK字符编码解压: {}", e.getMessage());
            return unZip(zipFile, Charset.forName("GBK"));
        }
    }


    /**
     * 解压成inputStream
     *
     * @param zipFile 压缩文件
     * @return 每个文件名以及对应InputStream流
     */
    public static Map<String, InputStream> unZipToInputStream(File zipFile) {
        Map<String, InputStream> map = new HashMap<>(8);
        try {
            try (ZipFile zip = new ZipFile(zipFile)) {
                Enumeration<? extends ZipEntry> zipEntries = zip.entries();
                while (true) {
                    if (!zipEntries.hasMoreElements()) {
                        return map;
                    }
                    ZipEntry entry = zipEntries.nextElement();
                    String entryName = entry.getName();
                    map.put(entryName, IoUtil.toByteArrayInputStream(zip.getInputStream(entry)));
                }
            }
        } catch (IOException e) {
            log.warn("ZipUtil | unZip: {}", e.getMessage(), e);
        }
        return Collections.emptyMap();
    }

}
